﻿using System;
using System.Text;
using System.Threading.Tasks;
using AbpZero.Web;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.ExceptionHandling;
using Volo.Abp.Json;

namespace AbpZero.Filters
{
    public class ExceptionFilter : AbpExceptionFilter
    {
        private readonly IExceptionToErrorInfoConverter _errorInfoConverter;
        private readonly AbpExceptionHandlingOptions _exceptionHandlingOptions;
        private readonly IJsonSerializer _jsonSerializer;
        private readonly IHttpExceptionStatusCodeFinder _statusCodeFinder;

        public ExceptionFilter(IExceptionToErrorInfoConverter errorInfoConverter,
            IHttpExceptionStatusCodeFinder statusCodeFinder, IJsonSerializer jsonSerializer,
            IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions) : base(errorInfoConverter, statusCodeFinder,
            jsonSerializer, exceptionHandlingOptions)
        {
            _errorInfoConverter = errorInfoConverter;
            _statusCodeFinder = statusCodeFinder;
            _jsonSerializer = jsonSerializer;
            _exceptionHandlingOptions = exceptionHandlingOptions.Value;
        }

        protected override bool ShouldHandleException(ExceptionContext context)
        {
            // return base.ShouldHandleException(context);
            return true;
        }


        protected override async Task HandleAndWrapException(ExceptionContext context)
        {
            context.HttpContext.Response.Headers.Add("_AbpErrorFormat", (StringValues) "true");
            context.HttpContext.Response.StatusCode = StatusCodes.Status200OK;

            var error = _errorInfoConverter.Convert(context.Exception,
                _exceptionHandlingOptions.SendExceptionsDetailsToClients);

            context.Result = new ObjectResult(new AjaxResponse
            {
                Code = (int) _statusCodeFinder.GetStatusCode(context.HttpContext, context.Exception),
                Message = error.Message,
                Details = error.Details,
                Result = null
            });
            var logLevel = context.Exception.GetLogLevel();
            var stringBuilder = new StringBuilder();
            stringBuilder.AppendLine("---------- RemoteServiceErrorInfo ----------");
            stringBuilder.AppendLine(_jsonSerializer.Serialize(error, indented: true));
            Logger.LogWithLevel(logLevel, stringBuilder.ToString());
            Logger.LogException(context.Exception, logLevel);
            await context.HttpContext.RequestServices.GetRequiredService<IExceptionNotifier>()
                .NotifyAsync(new ExceptionNotificationContext(context.Exception)).ConfigureAwait(false);
            context.Exception = null;
        }
    }
}